package com.shop.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shop.Redis.RedisService;
import com.shop.Redis.UserKey;
import com.shop.config.DateJsonValueProcessor;
import com.shop.dao.UserMapper;
import com.shop.exception.GlobalException;
import com.shop.pojo.Cart;
import com.shop.pojo.GoodsCollection;
import com.shop.pojo.User;
import com.shop.result.CodeMsg;
import com.shop.result.JsonResult;
import com.shop.service.LoginService;
import com.shop.util.BaseUtil;
import com.shop.util.MD5Util;
import com.shop.vo.LoginVo;
import net.sf.json.JSONArray;
import net.sf.json.JsonConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import org.springframework.data.mongodb.core.query.Query;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private RedisService redisService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MongoTemplate mongoTemplate;

    public static final String COOKIE_NAME_TOKEN = "token";

    /*定义集合名称*/
    private static final String collectionName = "user";

    //登录验证模块
    @Override
    public String login(HttpServletRequest request,HttpServletResponse response) {
        String account = request.getParameter("account");    //账号，默认是手机号码
        String inputPass = request.getParameter("password").replace(" ","");    //密码

        //判断当前账号是否存在MongoDB
        User user = getByAccount(account);
        if (user == null) {
            throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
        }

        //验证密码
        String dbPass = user.getPassword();
        String calcPw = MD5Util.inputPassToFormPass(inputPass);   //第一次加密
        String dbPw = MD5Util.formPassToDBPass(calcPw, BaseUtil.Feature_Code);  //第二次加密
        if (!dbPw.equals(dbPass)) {
            throw new GlobalException(CodeMsg.PASSWORD_ERROR);
        }

        //修改登录时间
        user.setLastLoginTime(new Date());

        /*Mysql操作*/
//        userMapper.updateByPrimaryKey(user);

        /*MongoDB操作*/
        Query query = new Query();
        query.addCriteria(Criteria.where("userName").is(user.getUserName()));
        query.addCriteria(Criteria.where("password").is(user.getPassword()));
        Update update = new Update();
        update.set("createTime",new Date());
        mongoTemplate.updateMulti(query,update,collectionName);

        //生成唯一id作为token
        String token = BaseUtil.getSID();
        addCookie(response, token, user);
        return token;
    }

    //注册验证模块
    @Override
    public JsonResult regsiter(User user) {
        //判断注册的手机号码是否唯一
        /*Mysql操作*/
//        User isExistUser = userMapper.selectByPhone(user.getPhone());

        /*MongoDB操作*/
        Query query = new Query();
        query.addCriteria(Criteria.where("phone").is(user.getPhone()));
        User isExistUser = mongoTemplate.findOne(query, User.class, collectionName);

        if (isExistUser != null){
            return new JsonResult(false,"手机号已被注册！");
        }

        //将密码进行二次加密
        String calcPw = MD5Util.inputPassToFormPass(user.getPassword());   //第一次加密
        String dbPw = MD5Util.formPassToDBPass(calcPw, BaseUtil.Feature_Code);  //第二次加密

        //把用户数据写入数据库
        user.setUserId(BaseUtil.getSID());
        user.setPassword(dbPw);
        user.setCreateTime(new Date());

        /*Mysql操作*/
//        userMapper.insert(user);

        /*MongoDB操作*/
        mongoTemplate.insert(user,collectionName);

        return new JsonResult(true,"注册账号成功！");
    }

    //读取用户信息
    public User getByAccount(String account) {
        User user = null;

        /*Redis操作*/
//        //对象缓存
//        user = redisService.get(UserKey.getByAccount, "" + account, User.class);
//        if (user != null) {
//            return user;
//        }
//
//        //取数据库
//        user = userMapper.selectByPhone(account);
//
//        //再存入缓存
//        if (user != null) {
//            redisService.set(UserKey.getByAccount, "" + account, user);
//        }

        /*MongoDB操作*/
        Query query = new Query();
        query.addCriteria(Criteria.where("userName").is(account));
        user = mongoTemplate.findOne(query,User.class,collectionName);

        return user;
    }

    /**
     * 将token做为key，用户信息做为value 存入redis模拟session
     * 同时将token存入cookie，保存登录状态
     */
    public void addCookie(HttpServletResponse response, String token, User user) {

        /*Redis操作*/
//        redisService.set(UserKey.token, token, user);

        /*MongoDB操作*/
        Query query = new Query();
        query.addCriteria(Criteria.where("token").is(token));
        query.fields().include(collectionName); //只显示用户信息
        query.fields().exclude("_id");  //不显示MongoDB数据库中生成的id值
        Map<String,Object> map = mongoTemplate.findOne(query, Map.class, "loginToken");   //查询MongoDB中单条token对应的用户信息

        JsonConfig cfg = new JsonConfig();
        cfg.setExcludes(new String[]{"handler","hibernateLazyInitializer"});
        cfg.registerJsonValueProcessor(Date.class, new DateJsonValueProcessor());

        JSONArray jsonArray = JSONArray.fromObject(map,cfg);

        Update update = new Update();
        if(map != null){    //token不为空，则为更新数据
            Map<String,Object> dataParam = BaseUtil.json2Map(jsonArray.get(0).toString());
            String cartJson = BaseUtil.toJson(dataParam.get("user").toString());
            User old_user = JSONObject.parseObject(cartJson, User.class);
            if(old_user != null){
                update.set(collectionName, old_user);
            }

        }else{  //token不为空，,直接添加信息即可
            update.set(collectionName, user);
        }

        update.set("createdAt",new Date());
        mongoTemplate.upsert(query,update, User.class,"loginToken");

        Cookie cookie = new Cookie(COOKIE_NAME_TOKEN, token);
        cookie.setMaxAge(UserKey.token.expireSeconds());
        cookie.setPath("/");//设置为网站根目录
        response.addCookie(cookie);
    }

    /*根据token获取用户信息*/
    public User getUserByToken(String token) {
        User user = null;

        /*Redis操作*/
//        user = redisService.get(UserKey.token,token,User.class);

        /*MongoDB操作*/
        Query query = new Query();
        query.addCriteria(Criteria.where("token").is(token));
        query.fields().include(collectionName); //只显示用户信息
        query.fields().exclude("_id");  //不显示MongoDB数据库中生成的id值

        //格式化json中的时间，避免转换成Java类对象时出现异常
        JsonConfig cfg = new JsonConfig();
        cfg.setExcludes(new String[]{"handler","hibernateLazyInitializer"});
        cfg.registerJsonValueProcessor(Date.class, new DateJsonValueProcessor());

        //在loginToken中查询是否有对应用户账号信息
        Map<String,Object> map = mongoTemplate.findOne(query, Map.class, "loginToken");
        if(map == null){
            return user;
        }

        JSONArray jsonArray = JSONArray.fromObject(map,cfg);

        //如果有，则返回对应的用户账号信息
        if(jsonArray.size() > 0){
            Map<String,Object> dataMap = BaseUtil.json2Map(jsonArray.get(0).toString());
            String cartJson = BaseUtil.toJson(dataMap.get(collectionName).toString());
            user = JSONObject.parseObject(cartJson, User.class);
        }

        return user;
    }

    //判断当前用户是否过期
    public boolean getUserIsTimeout(HttpServletRequest request,HttpServletResponse response,String token){
        boolean isCookie = false;
        User userInfo = getUserByToken(token);     //获取用户登录后保存在redis中的token
        Cookie[] cookies = request.getCookies();        //获取前端cookie数组
        if(cookies != null && StringUtils.isNotEmpty(token)){
            for(Cookie cookie : cookies){
                if(token.equals(cookie.getValue().toString())){
                    isCookie = true;
                    addCookie(response,token,userInfo);
                    break;
                }
            }

        }

        return isCookie;
    }

}
